home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 1993 May
/
Info-Mac_II_May_1993.to_.sit
/
Info-Mac II (May 1993).toast
/
Unix
/
Digest Reader 2.0.txt
< prev
next >
Wrap
Internet Message Format
|
1992-08-29
|
50KB
Date: Tue, 19 Nov 91 08:24:39 EST
From: dbbrown@eastrg2.cray.com (Dan Brown)
Subject: [*] digest-reader.txt (Version 2)
Here is Version 2 of digest-reader.txt, that I submitted earlier this
year. The changes were made by Michael Kimura (mnk@rdac.dnet.hac.com),
who uses the program alot and made to very useful improvements. Just
some of the major improvements include.
o The program has been ported to work with VMS/VAXC as well as UNIX/C
and has been tested in both environments.
o You now have the ability to extract individual articles from the
digest being read.
o The article recognition algorithm has been generalized to accomodate
many other digests created by other interest groups with similar
formats. Some of the other digests tested are BIG-LAN DIGEST,
RISKS-LIST: RISKS-FORUM Digest, Telecom Privacy Digest,
TELECOM Digest.
o ``dig'' now processes multiple arguments (digests) specified
on the command line (Works for VMS as well).
o The article menu contains both the subject and the author
(if it fits on the line).
o Added code to display the percent remaining of the article (nn%)
to the prompt while reading an article.
o It seemed more natural for continus pressing of return to take you
through the current article and then to the next article
than having pressing return take you back to the article
menu.
o Changed the Previous and Next processing so that
Previous and Next will "wrap" around back to the beginning
or end in either the topic display or while displaying articles.
o In conjunction with the change to having "ret" take you to
the next article instead of the article menu, I found I would
like to know what the next article's subject is. So I
reduced the number of lines displayed by one so that the
next article's subject can be displayed just before the prompt
when the current article has been completely displayed.
o Many other cosmetic changes.
I just want to thank Mike for taking the time to improve on the program.
I hope everyone who uses this program will appreciate the enhancements made by
Mike.
Enjoy,
Dan Brown
---------------------------------< digest-reader.txt Follows >---------------
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#if VAXC
#include rmsdef /* RMS DEFinitions (status codes for LIB$FIND_FILE) */
#endif
/*
- Compile line: cc dig.c -o dig
-
- Command line: dig [digest]
-
- Written by: Dan Brown (dbbrown@eastrg2.cray.com)
-
- Modified by: Michael Kimura (mnk@rdac.dnet.hac.com) 10/11/91
-
- o Made program capable of reading most digests (used to read
- only Info-Mac consistently) Had to change beginning of article
- logic to look for Hyphens instead of "Date:" (not all digests
- have "Date:" as first line of each article).
-
- o Added extract command to extract the article being displayed
- to a file.
-
- o Made first article (which is the digest header) article 0 instead
- of article 1 and changed the total number of articles to not
- include article 0. Program now parses either the digest title
- line or the first Subject: line to determine the digest name,
- volume number, and issue number and displays this information
- in the prompt line.
-
- o Increased MAX_ARTICLES from 75 to 100 (i.e. 99 articles plus
- article 0) and added boundary checking to make sure a digest
- with more than 99 articles doesn't crash this program. A
- warning message is generated for digests with >99 articles.
-
- o Made VAX C compatible.
- - fseek() in VAX C works fine for stream files but most
- other files you can only seek to locations returned by
- ftell(). Doing arithmetic on offsets returned by ftell()
- in VAX C produces incorrect results. Modified the code
- to call ftell() *before* reading the next record.
-
- - "lines" conflicts with VAX C run-time library, changed
- "lines" to "xlines"
-
- - VAX C run-time library does not contain the routine
- "bzero()" so added "bzero()" to this file.
-
- - VAX C I/O eats a totally blank line output after user
- input to a prompt, added logic to output a line with a
- space to force out blank line after user input if VAX C.
-
- Modified by: Michael Kimura (mnk@rdac.dnet.hac.com) 11/12/91
-
- o Added code to process all arguments as digest names. Also
- added code so that under VAXC it will process wildcard
- specifications in arguments.
-
- o Added code to parse the "personal name" out of the From: line
- and to append " (personal name)" to the subject.
-
- o Changed call from bzero() to memset() since memset() is in
- the VAX C run-time library.
-
- o Added percent remaining of the article (nn%) to the prompt
- while reading an article.
-
- o Changed Previous and Next processing so that Previous and
- Next will "wrap" around back to the beginning or end in
- either the topic display or while displaying articles. Hence,
- after displaying the last article, Next will take you to
- article 0. Also changed "ret" to be "Next" instead of
- "return to menu". This way pressing "ret" while displaying
- articles will take you through all of the articles.
-
- o Reduced the number of lines displayed by one so that the
- next article's subject is displayed just before the prompt
- when the current article has been completely displayed.
*/
/* Pre-Processor Definitions Section */
#define MAX_FILE_LEN 81 /* Maximum file name length - 1 */
#define MAX_ARTICLES 100 /* Maximum number of articles */
#define MAX_ANS 5 /* Maximum answer size */
#define LINE_LEN 81 /* Maximum Subject/From line len - 1 */
#define PROMPT_LINES 3 /* Number of menu prompt lines */
#define COLS 81 /* Number columns on the screen */
#define OUTPUT 0 /* Output indicator */
#define INPUT 1 /* Input indicator */
/*
-- Minimum number of working lines enough for at least 1 article,
-- and menu prompt.
*/
#define MIN_LINES (PROMPT_LINES + 1)
/* Line identification values */
#define DIGEST_TITLE 0 /* Digest Title line */
#define SUBJECT 1 /* Subject line */
#define FROM 2 /* From line */
#define HYPHENS 3 /* Line with leading hyphens */
#define UNKNOWN 4 /* Unknown line type */
/* Menu Selections */
#define QUIT -1 /* QUIT menu selection */
#define HELP -2 /* HELP menu selection */
#define NEXT -3 /* NEXT menu selection */
#define PREVIOUS -4 /* PREVIOUS menu selection */
#define ILLEAGAL -5 /* ILLEAGAL user reponse */
#define FIRST_PAGE -6 /* Goto the first menu page */
/* Screen clear macro */
#if !VAXC
#define clear() (void) system("clear")
#else
#define clear() ;
/* This can be used on VMS but WARNING, it spawns a subprocess so */
/* it's can be very slow */
/*
#define clear() (void) system("type/page nl:")
*/
#endif
/* Uncomment this and comment above if necessary */
/*
#define clear()
*/
/* External definitions section */
extern char *memset();
/* Global variables Section */
/* Program ident string */
static char id[] = "@(#)dig v2.0 11/12/91 dbbrown@eastrg2.cray.com/mnk@rdac.dnet.hac.com";
char errmsg[256]; /* Error message storage */
char digest[LINE_LEN]; /* Digest name */
int volume; /* Volume number */
int issue; /* Issue number */
int xlines = 24; /* Number of lines on screen */
/* Selected info extracted from the given digest */
typedef struct {
long offset; /* Offset to begining of article */
int num_lines; /* Number of lines in the article */
char subject[LINE_LEN]; /* Extracted "Subject" from article */
char from[LINE_LEN]; /* Extracted "From" from article */
} article;
main(argc, argv)
int argc;
char **argv;
{
char fname[MAX_FILE_LEN]; /* input file name */
int result; /* Return value of some functions */
char *cptr;
void process_digest(); /* Process the given digest */
int arg; /* argument index */
#if VAXC
unsigned long find_file(); /* Interface routine to LIB$FIND_FILE */
unsigned long succ; /* Result code from find_file() */
#endif
/*
-- Determine the number of lines on the screen. If the environment
-- variable LINES is not defined then the program will default to
-- it's initial value.
*/
cptr = getenv("LINES");
if (cptr != (char *) NULL)
{
/*
-- A LINES environment variable was found. Convert the
-- returned string to an integer value.
*/
result = atoi(cptr);
/*
-- Determine if the value of the LINES variable has an
-- integer value greater than MIN_LINES. 0 indicates either the
-- value of LINES is 0 or it is a non-integer value.
*/
if (result >= MIN_LINES)
{
/* The variable has a valid integer */
xlines = result;
}
}
/* Determine the input file name */
if (argc == 1)
{
/*
-- No file name was given on the command line. Get the filename
-- from the users.
*/
result = getfilename(fname,INPUT);
/* Determine if the user selected quit */
if (result == -1)
{
/* The user elected to quit the program */
clear();
(void) printf("\n\tExiting (%s).\n\n", argv[0]);
exit(0);
}
/* Process the digest */
process_digest(fname);
}
else
{
/*
-- Take the rest of the arguments as file names and
-- process them
*/
for (arg = 1; arg < argc; arg++)
{
#if !VAXC
/* Process the digest(s) */
process_digest(argv[arg]);
#else
do
{
succ = find_file(argv[arg],fname,sizeof(fname));
if (succ != RMS$_NMF)
process_digest(fname);
} while (succ == RMS$_NORMAL);
#endif
}
}
}
/* Process the given digest */
void process_digest(fname)
char *fname; /* input file name */
{
FILE *fp; /* Input file pointer */
int result; /* Result returned by functions */
article articles[MAX_ARTICLES]; /* Article info from digest */
int num_articles; /* Total number of articles */
int start; /* Index to first display article */
int max_articles; /* Maximum articles in menu */
int cur_articles; /* Number of articles to display */
int last_article; /* Pointer to last article */
int done; /* Loop control variable */
void display_article();
/* Initialize local variables */
memset((char *) articles, 0, sizeof(articles));
/* Attempt to open the digest */
fp = fopen(fname, "r");
/* Determine if there was an error opening the file */
if (fp == (FILE *) NULL)
{
/*
-- There was an error opening the digest file, report the
-- error and exit the function.
*/
(void) sprintf(errmsg, "%s (%d): Error opening file '%s'",
__FILE__, __LINE__, fname);
(void) perror(errmsg);
}
else
{
/* The digest file was successfully opened. */
(void) strcpy(digest,"Digest");
volume = 0;
issue = 0;
/* Get the file's article information */
result = get_art_info(fp, fname, articles, &num_articles);
/* Determine if the function was successful */
if (result == 0)
{
/* The function was successful */
/*
-- Set the initial values for the starting article and
-- number of articles to display on the menu to list in
-- the menu.
*/
start = 0;
last_article = num_articles - 1; /* Zero based array */
max_articles = xlines - PROMPT_LINES;
if ((start + max_articles - 1) > last_article)
{
/*
-- There are fewer articles to display than the
-- maximum number displayable. Calculate the actual
-- number of articles available.
*/
cur_articles = num_articles - start;
}
else
{
/* We can safely display the max number of articles. */
cur_articles = max_articles;
}
/* Do user actions until the user selects quit */
done = 0;
while (!done)
{
/* Display the menu of selections */
result = display_menu(articles, start, cur_articles,
num_articles);
/* execute the users request */
switch(result)
{
case FIRST_PAGE:
start = 0;
/*
-- Determine if there are fewer articles
-- available than can be maximumly displayed.
*/
if ((start + max_articles - 1) > last_article)
{
/*
-- There are fewer articles to display than
-- the maximum number displayable.
-- Calculate the actual number of articles
-- available.
*/
cur_articles = num_articles - start;
}
else
{
/*
-- We can safely display the maximum
-- number of articles.
*/
cur_articles = max_articles;
}
break;
case NEXT: /* Next page of Articles */
if (start + max_articles <= last_article)
{
start += max_articles;
/*
-- Determine if there are fewer articles
-- available than can be maximumly
-- displayed.
*/
if ((start + max_articles - 1) >
last_article)
{
/*
-- There are fewer articles to display
-- than the maximum number displayable.
-- Calculate the actual number of
-- articles available.
*/
cur_articles = num_articles - start;
}
else
{
/*
-- We can safely display the maximum
-- number of articles.
*/
cur_articles = max_articles;
}
}
break;
case PREVIOUS: /* Previous page of Articles */
/* The user selected previous page */
start -= max_articles;
if (start < 0)
start = last_article -
(last_article % max_articles);
/*
-- Determine if there are fewer articles
-- available than can be maximumly displayed.
*/
if ((start + max_articles - 1) > last_article)
{
/*
-- There are fewer articles to display than
-- the maximum number displayable.
-- Calculate the actual number of articles
-- available.
*/
cur_articles = num_articles - start;
}
else
{
/*
-- We can safely display the maximum
-- number of articles.
*/
cur_articles = max_articles;
}
break;
case QUIT: /* Quit the program */
clear();
done = 1;
break;
case ILLEAGAL:
break;
default:
/* Test for article number here */
if (result > num_articles - 1)
{
clear();
(void) printf(
"Invalid article number %d\n", result);
sleep(1);
}
else
{
/* Display the article */
display_article(fp, fname, result,
articles, num_articles);
}
break;
}
}
}
/* Close the open file */
(void) fclose(fp);
}
}
/*
-- This functions extracts article location, num_lines, and Subject
-- and From lines from each article found in the given file.
*/
int get_art_info(fp, fname, articles, num_articles)
FILE *fp; /* Input file pointer */
char *fname; /* Digest file name */
article articles[]; /* an array of article information */
int *num_articles; /* Total number of articles in digest */
{
int return_value; /* Function return value */
int art_count; /* Article count */
int first_art; /* Set if it is the first article */
int done; /* Loop control variable */
int total_lines; /* number of lines in digest */
int last_line; /* Last line of previous article */
char buf[BUFSIZ]; /* Input buffer */
char *cptr; /* ptr into the Input buffer */
char *cptr2; /* another ptr into the Input buffer */
int len; /* Length of string */
char name[BUFSIZ]; /* Name from From: line */
void get_name(); /* Routine to get personal name from From: line */
/* Initialize local variables */
return_value = 0;
art_count = 0;
done = 0;
total_lines = 0;
last_line = 0;
first_art = 1;
/* Start from the beginning of the file */
(void) fseek(fp, 0L, 0);
/* Process each article found in the file */
while (!done)
{
/* Get the next line in the file */
if (fgets(buf, BUFSIZ, fp) != (char *) NULL)
{
/* increment the number of lines in the article */
total_lines++;
/* Determine the type of line just read */
switch(detline(buf))
{
case DIGEST_TITLE: /* A digest title line */
/* Determine if this is the first article */
if (first_art == 1)
{
/* This is the first article */
/* Record digest title line as article[0].subject */
(void) strncpy(articles[0].subject,buf,LINE_LEN - 1);
articles[0].subject[LINE_LEN - 1] = '\0';
/* Remove the trailing newline */
cptr = strchr(articles[art_count].subject,
'\n');
if (cptr != (char *) NULL)
*cptr = '\0';
break;
}
case HYPHENS: /* A hyphen line */
/* Determine if this is the first article */
if (first_art == 1)
{
/* This is the first article */
/* Determine the start of the article */
articles[0].offset = 0L;
/* Set first article to false */
first_art = 0;
}
/* Update the article count */
art_count++;
/* Update the num_lines in prev. article */
articles[art_count - 1].num_lines =
total_lines - last_line;
/* Attempt to add personal name to subject */
if (articles[art_count-1].subject[0] != '\0' &&
articles[art_count-1].from[0] != '\0')
{
(void) get_name(articles[art_count-1].from,name);
(void) strncat(articles[art_count-1].subject,name,
LINE_LEN-1-strlen(articles[art_count-1].subject));
}
/* Update the last line */
last_line = total_lines;
/* Have we read the maximum number of articles? */
if (art_count < MAX_ARTICLES)
{
/* Determine the start of the next article */
articles[art_count].offset = ftell(fp);
}
else
{
/* Pass on the number of articles in digest */
*num_articles = MAX_ARTICLES;
(void) printf(
"Warning! -- Digest contains more than %d articles, remainder ignored.\n",
MAX_ARTICLES-1);
/* Sleep awhile to allow user to read msg */
sleep(11);
/* Exit the loop */
done = 1;
}
break;
case FROM: /* A From line */
/* advance past the From: prefix */
cptr = strchr(buf, ':') + 1;
/*
-- Copy the contents of the from line, if there is
-- nothing already stored. I want only the first
-- occurance.
*/
if (articles[art_count].from[0] == '\0')
{
(void) strncpy(articles[art_count].from,
cptr, LINE_LEN - 1);
articles[art_count].from[LINE_LEN - 1] = '\0';
/* Remove the trailing newline */
cptr = strchr(articles[art_count].from, '\n');
if (cptr != (char *) NULL)
*cptr = '\0';
}
break;
case SUBJECT: /* A Subject line */
/* advance past the Subject: prefix */
cptr = strchr(buf, ':') + 1;
/*
-- Copy the contents of the subject line, if there
-- is nothing already stored. I want only the
-- first occurance.
*/
if (articles[art_count].subject[0] == '\0')
{
(void) strncpy(articles[art_count].subject,
cptr, LINE_LEN - 1);
articles[art_count].subject[LINE_LEN - 1] =
'\0';
/* Remove the trailing newline */
cptr = strchr(articles[art_count].subject,
'\n');
if (cptr != (char *) NULL)
*cptr = '\0';
}
/* Determine if this is the first article */
if (first_art == 1)
{
/* This is the first article */
/* Attempt to retreive info from subject line */
cptr = strchr(buf,':') + 2;
cptr2 = strstr(cptr,"Digest V");
if (cptr2 == (char *) NULL)
cptr2 = strstr(cptr,"DIGEST V");
if (cptr2 != (char *) NULL)
{
/* Retreive the Digest Name */
cptr2 += strlen("Digest");
len = cptr2 - cptr;
(void) strncpy(digest,cptr,len);
digest[len] = '\0';
/* Retreive the Issue Number */
cptr = strchr(cptr,'#');
if (cptr != (char *) NULL)
{
cptr++;
issue = atoi(cptr);
}
/* Retreive the Volume Number */
cptr -= 2;
*cptr = '\0';
cptr2 += 2;
volume = atoi(cptr2);
}
}
break;
default: /* All other lines */
break;
}
}
else
{
/* EOF or error */
/* Determine if there was an error reading the file */
if (ferror(fp))
{
/* Error reading the file */
(void) sprintf(errmsg,
"%s (%d): Error reading file '%s'", __FILE__,
__LINE__, fname);
perror(errmsg);
return_value = -1;
}
else
{
/* EOF was reached. */
/* Pass on the number of articles in digest */
*num_articles = art_count;
}
/* Exit the loop */
done = 1;
}
}
/*
-- This is a somewhat feeble attempt to determine if the file was a
-- valid digest. It assumes that at least 2 articles are found
-- that fit the expected format and if found then it is a valid
-- digest.
*/
if (return_value != -1 && art_count < 1)
{
/* The digest was an invalid file. */
(void) fprintf(stderr, "%s (%d): Invalid Digest file '%s'.\n",
__FILE__, __LINE__, fname);
return_value = -1;
}
return(return_value);
}
/* Attempt to extract the personal name from the From: line */
void get_name(from,name)
char *from; /* From: line minus "From: " */
char *name; /* Personal Name */
{
char *cptr; /* ptr into the given line */
char *cptr2; /* ptr into the given line */
strcpy(name," (");
from++;
if (*from == '\"')
{
from++;
if ( (cptr = strchr(from,'\"')) != (char *) NULL)
{
strncat(name,from,cptr-from);
strcat(name,")");
}
}
else
if ( (cptr = strstr(from," <")) != (char *) NULL)
{
strncat(name,from,cptr-from);
strcat(name,")");
}
else
if ( (cptr = strstr(from," (")) != (char *) NULL)
{
cptr += (sizeof(" (") - 1);
if ( (cptr2 = strchr(cptr,')')) != (char *) NULL)
strncat(name,cptr,cptr2-cptr+1); /* Includes ")" */
}
if (strcmp(" (",name) == 0)
{
strcat(name,from);
strcat(name,")");
}
}
/* Determine the type of line */
int detline(line)
char *line; /* Line to evaluate */
{
char *cptr; /* ptr into the given line */
int i; /* Loop control variable */
int return_value; /* Return value of function */
char upper[BUFSIZ]; /* Upper case copies from line */
/* convert line to upper case. */
for (i = 0, cptr = line; *(cptr + i) != '\0' ; i++)
*(upper + i) = toupper(*(cptr + i));
*(upper + i) = '\0';
/* Determine the type of line it is */
if (strncmp("FROM:", upper, 5) == 0)
{
/* It is a From line */
return_value = FROM;
}
else if ( (strncmp("SUBJECT:", upper, 8) == 0) ||
(strncmp("SUBJ:", upper, 5) == 0) )
{
/* It is a Subject line */
return_value = SUBJECT;
}
else if (strncmp("--------", upper, 8) == 0)
{
/* It is a hypen line */
return_value = HYPHENS;
}
else if ( (strstr(upper," DIGEST ") != (char *) NULL) &&
(strstr(upper," VOLUME ") != (char *) NULL) &&
(strstr(upper," : ISSUE") != (char *) NULL) )
{
/* It is a digest title line */
return_value = DIGEST_TITLE;
/* Retrieve the Issue Number from the line */
cptr = strstr(upper," : ISSUE") + strlen(" : ISSUE");
if (*cptr == ':')
cptr++;
issue = atoi(cptr);
/* Retrieve the Volume Number from the line */
cptr -= strlen(" : ISSUE");
*cptr = '\0';
volume = atoi(strstr(upper," VOLUME ") + strlen(" VOLUME "));
/* Retrieve the Digest Name from the line */
i = strstr(upper," DIGEST ") + strlen (" DIGEST") - &upper[0];
(void) strncpy(digest,line,i);
digest[i] = '\0';
}
else
{
/* It is an undetermined line type. */
return_value = UNKNOWN;
}
return(return_value);
}
/* This function gets the filename from the user. */
int getfilename(fname,in_or_out)
char fname[]; /* File name retrieved from user */
int in_or_out; /* INPUT or OUTPUT indicator */
{
char answer[MAX_FILE_LEN]; /* users response */
char *front; /* points to front of the file name */
char *cptr; /* used to NULL terminate file name */
int done; /* Loop control variable */
int return_value; /* Return value of the function */
/*
-- Retrieve the file name from the user. Loop until the user
-- supplies a file name or q is selected.
*/
return_value = -1;
done = 0;
while (!done)
{
if (in_or_out == INPUT)
{
/* Clear the screen and prompt the user for a file name */
clear();
(void) printf("\nEnter digest file name (q = quit): ");
}
else
{
/* Prompt the user for an output file name */
(void) printf("\nEnter output file name (q = quit): ");
}
/* Get the users response */
if (fgets(answer, MAX_FILE_LEN, stdin) == (char *) NULL)
{
/* An Error or End of file was received. Exit the program */
done = 1;
}
else
{
/* Got a users response */
/* Point to the first non-white space character */
front = answer;
while (isspace(*front))
front++;
/* Determine an appropriate action based on the response. */
if (*front == '\0')
{
/*
-- The user just hit return. Report to the user to
-- use 'q' to quit or enter a file name.
*/
(void) printf("\tEnter 'q' to quit or a file name.\n");
sleep(1);
}
else if (strcmp(front, "q\n") == 0)
{
/* The user wants to quit. */
done = 1;
}
else
{
/* A file name was given */
cptr = front;
/* Remove the newline from the file name */
while (!isspace(*cptr))
cptr++;
*cptr = '\0';
/* Copy the file name to fname */
(void) strcpy(fname, front);
/* Exit the loop and return to the calling function */
done = 1;
return_value = 0;
}
}
}
return(return_value);
}
/* Display a list of available articles */
int display_menu(articles, start, num_articles, total)
article articles[]; /* Array listing available articles */
int start; /* First article to display */
int num_articles; /* num articles to display */
int total; /* total number of articles */
{
int i; /* Loop control variable */
char answer[MAX_ANS]; /* Users answer to prompt */
char *front; /* Pointer to front of answer */
int return_value; /* Function return value */
/* Clear the screen */
clear();
/* Print out the list of articles */
for (i = start; i < start + num_articles; i++)
{
if (articles[i].subject[0] != '\0')
(void) printf("%02d> %.75s\n", i, articles[i].subject);
else
(void) printf("%02d> %.75s\n", i, articles[i].from);
}
/*
-- Print out blank lines to ensure that the prompt is at the
-- bottom of the page.
*/
for (i = 0; i < xlines - PROMPT_LINES - num_articles; i++)
(void) printf("\n");
/*
-- Print out the menu prompt. The number of lines required should
-- be exactly equal to PROMPT_LINES in order for the program to
-- work correctly.
*/
/* Prompt line 1 */
(void) printf("\n");
/* Prompt line 2 */
(void) printf("--- (%s %d:%d, Articles (%d - %d) of %d) ---\n",
digest, volume, issue, start, start + num_articles - 1, total - 1);
/* Prompt line 3 */
(void) printf( "Article number, (n)ext, (p)revious, or (q)uit: ");
/* Read in the users response */
(void) fflush(stdin);
if (fgets(answer, MAX_FILE_LEN, stdin) == (char *) NULL)
{
/* An Error or End of file was received. Exit the program */
return_value = QUIT;
}
else
{
/* Got a users response */
/* Point to the first non-white space character */
front = answer;
while (isspace(*front))
front++;
/* Determine an appropriate action based on the response. */
if (isalpha(*front))
{
/* The user entered a letter response */
switch (*front)
{
case 'p':
case 'P':
case 'b':
case 'B':
return_value = PREVIOUS;
break;
case 'n':
case 'N':
case 'f':
case 'F':
return_value = NEXT;
break;
case 'q':
case 'Q':
return_value = QUIT;
break;
default:
clear();
(void) printf("Invalid request %s", front);
sleep(1);
return_value = ILLEAGAL;
break;
}
}
else if (isdigit(*front))
{
/* The user entered an article number */
return_value = atoi(front);
}
else
{
/*
-- The user entered something other than a letter or a
-- number
*/
if (*front != '\0')
{
clear();
(void) printf("Invalid request %s", front);
sleep(1);
return_value = ILLEAGAL;
}
else
{
if ((start + (xlines - PROMPT_LINES)) <= (total - 1))
return_value = NEXT;
else
return_value = FIRST_PAGE;
}
}
}
return(return_value);
}
/* Display the article on the screen */
void display_article(fp, fname, article_num, articles, num_articles)
FILE *fp; /* input file */
char *fname; /* input file name */
int article_num; /* Index into articles, which article */
article articles[]; /* Array of article information */
int num_articles; /* number of articles */
{
int total; /* Total number of lines displayed */
int i; /* Loop control variable */
int count; /* number of lines displayed on screen */
int len; /* Length of a input line */
int inc; /* Line count increment number */
long curr_line; /* Offset to the current line */
char buf[BUFSIZ]; /* Input buffer */
int result; /* return from function calls */
int done; /* Loop control variable */
int prev_total; /* previous totals */
char answer[MAX_ANS]; /* Users answer to prompt */
char *front; /* Pointer to front of answer */
long curr_offset; /* Current offset in file */
void extract_article();
/* Seek to the articles location in the file */
result = fseek(fp, articles[article_num].offset, 0);
if (result == -1)
{
/* Error seeking in file */
clear();
(void) sprintf(errmsg, "%s (%d): Error seeking in file %s",
__FILE__, __LINE__, fname);
perror(errmsg);
}
else
{
/*
-- Since there was no error seeking in the file. I will assume
-- that all other I/O to the file will be good. (It just means
-- I was too lazy to check every call.)
*/
/* Initialize local variables */
total = 0;
/* Display the article */
done = 0;
while (!done)
{
/* Display the article 'lines - 1' lines at a time */
clear();
/* Store the current position */
curr_line = ftell(fp);
prev_total = total;
/* Display the article */
for (count = 0; total < articles[article_num].num_lines &&
count < xlines - 2; count++, total++)
{
curr_offset = ftell(fp); /* Record current offset */
(void) fgets(buf, BUFSIZ, fp);
/* Determine if the line will wrap on the screen */
len = strlen(buf);
if (len > COLS)
{
/*
-- The line will wrap on the screen. If the screen
-- WRAPS versus TRUNCATE. If your screen TRUNCATES
-- then set COLS to a large number.
*/
/* Determine the number of lines to add to count */
inc = len / COLS;
/*
-- Determine if the number of lines to add will
-- bring us over the allowable lines.
*/
if (count + inc >= xlines - 2)
{
/* The number of lines will be exceeded */
/* Back up one line in the input file */
(void) fseek(fp, curr_offset, 0);
/* Fill the rest of the page with newlines */
for(; count < xlines - 2; count++)
(void) printf("\n");
}
else
{
/*
-- The number of lines is below the number to
-- fit on a screen.
*/
count += inc;
(void) fputs(buf, stdout);
}
}
else
{
/* The line will not wrap */
#if !VAXC
(void) fputs(buf, stdout);
#else
if (len == 1 && count == 0)
{
/*
-- VMS eats a totally blank line after reading
-- input from terminal so output a line with a
-- space instead
*/
(void) fputs(" \n", stdout);
}
else
(void) fputs(buf, stdout);
#endif
}
}
/* Print the prompt */
if (total == articles[article_num].num_lines)
{
for(i = count; i < xlines - 2; i++)
(void) printf("\n");
if (article_num < num_articles - 1)
i = article_num + 1;
else
i = 0;
(void) printf("Next: %.73s\n", articles[i].subject);
(void) printf(
"--- #%d of %d (q)uit (t)op (n)ext (p)revious (e)xtract [ret - Next] (%d%%): ",
article_num, num_articles - 1, 100);
}
else
{
(void) printf("\n");
(void) printf(
"--- #%d of %d (q)uit (t)op (n)ext (p)revious (e)xtract [ret - More] (%d%%): ",
article_num, num_articles - 1,
total * 100 / articles[article_num].num_lines);
}
/* Clear out the input buffer */
(void) fflush(stdin);
/* Get the users response */
if (fgets(answer, MAX_FILE_LEN, stdin) == (char *) NULL)
{
/* An Error or End of file was received. */
done = 1;
}
else
{
/* Got a users response */
/* Point to the first non-white space character */
front = answer;
while (isspace(*front))
front++;
/*
-- Determine an appropriate action based on the
-- response.
*/
switch (*front)
{
case 'Q': /* Quit reading article */
case 'q':
done = 1; /* Exit the loop */
break;
case 'p': /* Previous Article */
case 'P':
/*
-- Go to the previous article and prepare to
-- print from the first line.
*/
total = 0;
article_num--;
if (article_num < 0)
article_num = num_articles - 1;
/* Goto the first line of the article */
(void) fseek(fp,
articles[article_num].offset, 0);
break;
case 't': /* Top of article */
case 'T':
/* Goto the first line of the article */
(void) fseek(fp, articles[article_num].offset,
0);
/* Set to print the first line */
total = 0;
break;
case '\0': /* Return */
/*
-- Determine if the whole article has been
-- displayed. If the whole article was not
-- diplayed, then return will show more of the
-- article.
*/
if (total < articles[article_num].num_lines)
break;
/*
-- If we get here then the whole article was
-- displayed so fall through to Next Article
-- code to display the next article.
*/
case 'n': /* Next Article */
case 'N':
/*
-- Advance to the next article and set to
-- print on the first line.
*/
total = 0;
article_num++;
if (article_num > num_articles - 1)
article_num = 0;
/* Goto the first line of the article */
(void) fseek(fp,
articles[article_num].offset, 0);
break;
case 'e': /* Extract article to a file */
case 'E':
(void) extract_article(fp, fname, article_num,
articles);
(void) fseek(fp, curr_line, 0);
total = prev_total;
break;
default:
clear();
(void) printf("Invalid response %s", front);
sleep(1);
(void) fseek(fp, curr_line, 0);
total = prev_total;
break;
}
}
} /* End while not done */
}
}
/* Extract the article to a file */
void extract_article(fp, fname, article_num, articles)
FILE *fp; /* input file */
char *fname; /* input file name */
int article_num; /* Index into articles, which article */
article articles[]; /* Array of article information */
{
int count; /* number of lines extracted */
char buf[BUFSIZ]; /* Input buffer */
int result; /* return from function calls */
FILE *ofp; /* output file */
char ofname[MAX_FILE_LEN]; /* output file name */
char full_name[BUFSIZ]; /* full file name of output file */
/* Get the name of the output file from the user */
result = getfilename(ofname,OUTPUT);
/* Determine if the user selected quit */
if (result == -1) return;
/* Attempt to open the output file */
ofp = fopen(ofname, "w");
/* Determine if there was an error opening the file */
if (ofp == (FILE *) NULL)
{
/*
-- There was an error opening the digest file, report the
-- error and exit the function.
*/
(void) sprintf(errmsg, "%s (%d): Error opening file '%s'",
__FILE__, __LINE__, ofname);
(void) perror(errmsg);
}
else
{
/* The output file was successfully opened. */
#if VAXC
/* In VAXC use fgetname to get the full name of the output file */
(void) fgetname(ofp,full_name);
#else
/* If not VAX simply use "ofname" as the full name */
(void) strcpy(full_name,ofname);
#endif
/* Seek to the articles location in the file */
result = fseek(fp, articles[article_num].offset, 0);
if (result == -1)
{
/* Error seeking in file */
clear();
(void) sprintf(errmsg, "%s (%d): Error seeking in file %s",
__FILE__, __LINE__, fname);
perror(errmsg);
}
else
{
/*
-- Since there was no error seeking in the file. I will assume
-- that all other I/O to the file will be good. (It just means
-- I was too lazy to check every call.)
*/
/* Extract the article */
for (count = 0; count < articles[article_num].num_lines; count++)
{
(void) fgets(buf, BUFSIZ, fp);
(void) fputs(buf, ofp);
}
(void) printf("Article #%d (%d lines) extracted to file '%s'\n",
article_num,articles[article_num].num_lines,full_name);
sleep(1);
}
/* Close the open file */
(void) fclose(ofp);
}
}
#if VAXC
/*----------------------------------------------------------------------*/
/* Find_File - Subroutine to call LIB$FIND_FILE */
/*----------------------------------------------------------------------*/
#include descrip
#define MULTIPLE 2
unsigned long find_file(fspec,fname,fname_len)
char *fspec;
char *fname;
long fname_len;
{
static int context=0;
register unsigned long succ;
register char *ptr;
struct dsc$descriptor_s fspec_d =
{strlen(fspec), DSC$K_DTYPE_T, DSC$K_CLASS_S, fspec};
struct dsc$descriptor_s fname_d =
{fname_len, DSC$K_DTYPE_T, DSC$K_CLASS_S, fname};
succ = LIB$FIND_FILE(&fspec_d,&fname_d,&context,0,0,0,&MULTIPLE);
fname[fname_len-1] = ' ';
for(ptr=fname; *ptr != ' '; ptr++)
;
*ptr = '\0';
return succ;
}
#endif